package com.phoenix.shuaidatabase.utils;

import com.phoenix.shuaidatabase.utils.ShuaiRateLimiter;

import java.util.ArrayList;
import java.util.concurrent.ConcurrentHashMap;

public class SlidingWindowRateLimiter implements ShuaiRateLimiter {

    private ConcurrentHashMap<String,SlidingWindow> resources;

    public SlidingWindowRateLimiter(ArrayList<String> resourceNames,int n) {
        resources = new ConcurrentHashMap<>();
        for(String resource : resourceNames) {
            resources.put(resource,new SlidingWindow(20,50,n));
        }
    }

    @Override
    public boolean tryAcquire(String resource) {
        return resources.get(resource).isAllowed();
    }

    private static class SlidingWindow {
        //滑动窗口总分块个数
        private int capacity = 60;
        private final int[] slidingWindow;
        //存储当前窗口请求量游标
        private int current = 0;
        //滑动窗口分块边界
        private long left = 0,right = 0;
        //滑动窗口分块大小
        private int minWindowSize = 10;
        //当前累计请求量
        private int requestCount = 0;
        //窗口请求量限制
        private int maxCount = 10;

        public SlidingWindow(int capacity,int minWindowSize,int maxCount) {
            this.capacity = capacity;
            this.minWindowSize = minWindowSize;
            this.maxCount = maxCount;
            this.slidingWindow = new int[capacity];
        }

        private void refreshWindow(long now) {
            if(right == 0) {
                right = now;
            }else {
                do {
                    current = (current + 1) % capacity;
                    requestCount -= slidingWindow[current];
                    slidingWindow[current] = 0;
                    right += minWindowSize;
                    System.out.println("time window reload timestamp: " + now + "left: " + left + "right: " + right);
                } while (now > right);
            }
            left = right - minWindowSize;
        }

        /*
        now 在 (left, right]里，判断请求量是否达到上限，否则该窗口请求加一
        now > right 移动到后面的窗口，并清空最初窗口的累计值
         */
        public synchronized boolean isAllowed() {
            long now = System.currentTimeMillis();
            if(now > right) {
                refreshWindow(now);
            }
            if(requestCount < maxCount) {
                slidingWindow[current]++;
                requestCount++;
                System.out.println("try acquire success! current requestCount:" + requestCount + " current:" + now + " left:" + left + " right:" + right);
                return true;
            }else {
                System.out.println("try acquire fail. current:" + now + " left:" + left + " right:" + right);
                return false;
            }
        }
    }
}
